package cn.itcast.nems.order.web.controller.o;

import cn.itcast.ic.common.bean.BizError;
import cn.itcast.ic.common.bean.BizHttpStatus;
import cn.itcast.ic.common.exception.BizException;
import cn.itcast.nems.common.account.AccountHolder;
import cn.itcast.nems.common.account.AccountInfo;
import cn.itcast.nems.common.service.BizNumberService;
import cn.itcast.nems.order.api.OrderApi;
import cn.itcast.nems.order.dao.entity.Order;
import cn.itcast.nems.order.dto.*;
import cn.itcast.nems.order.service.OrderPaymentFlowService;
import cn.itcast.nems.order.service.OrderService;
import cn.itcast.nems.order.web.util.OrderUtil;
import cn.itcast.nems.order.web.vo.*;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 
 * 订单
 *
 * @author 刘曙
 *
 * @version 
 *
 * @since 2023年9月11日
 */
@Slf4j
@RestController
@RequestMapping("/o/order")
@AllArgsConstructor
public class OrderController {
    
    private final OrderService orderService;
    private final OrderApi orderApi ;
    private final OrderPaymentFlowService orderPaymentFlowService;

    private final BizNumberService bizNumberService;

    /**
     *  
     * 功能描述：订单支付结果通知
     *
     * @param orderNo 订单号
     * @param paymentResult 支付结果明细
     * @return 订单支付流水号
     * 
     * @author 刘曙
     *
     * @since 2023年9月17日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    @PostMapping("/{orderNo}/payment/notify")
    public ResponseEntity<List<PaymentResultNotifyResultVO>> paymentResultNotify(@PathVariable("orderNo") @NotBlank(message = "订单号不能为空！") String orderNo, 
                                                 @RequestBody @Validated PaymentResultNotifyVO paymentResult) {
        String status = paymentResult.getStatus();
        validatePaymentResultStatus(status);
        if (PaymentResultStatusEnum.FAIL.toString().equalsIgnoreCase(status)) {
            log.warn("收到订单支付失败通知！订单号：{}，说明：{}", orderNo, paymentResult.getDescription());
            return ResponseEntity.ok(null);
        }
        
        List<String> flowNos = orderService.paymentSuccess(convertOrderPaymentResult(orderNo, paymentResult));
        return ResponseEntity.created(null).body(convertPaymentResultNotifyResult(flowNos));
    }
    
    /**
     * 
     * 功能描述：订单支付结果通知（通过BizOrderNo）
     *
     * @param paymentResult
     * @return
     * 
     * @author 刘曙
     *
     * @since 2023年9月17日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    @PostMapping("/payment/notify")
    public ResponseEntity<List<PaymentResultNotifyResultVO>> paymentResultNotifyByBizNo(@RequestBody @Validated PaymentResultNotifyVO paymentResult) {
        // 实现订单支付结果通知
        String status = paymentResult.getStatus();
        validatePaymentResultStatus(status);
        if (PaymentResultStatusEnum.FAIL.toString().equalsIgnoreCase(status)) {
            log.warn("收到订单支付失败通知！业务订单号：{}，说明：{}", paymentResult.getBizOrderNo(), paymentResult.getDescription());
            return ResponseEntity.ok(null);
        }
        final PaymentResultLineNotifyVO vo = paymentResult.getPaymentLines().get(0);
        final String createdBy = vo.getCreatedBy();
        if(StringUtils.hasText(createdBy) && createdBy.endsWith("@itcast.cn")){
            AccountInfo a = new AccountInfo(createdBy, "", "", "");
            AccountHolder.setAccountInfo(a);
        }
        try {
            List<String> flowNos = orderService.paymentSuccess(convertOrderPaymentResult("", paymentResult));
            return ResponseEntity.created(null).body(convertPaymentResultNotifyResult(flowNos));
        }finally {
            AccountHolder.clear();
        }
    }
    
    /**
     * 
     * 功能描述：校验支付结果状态
     *
     * @param status
     * 
     * @author 刘曙
     *
     * @since 2023年9月20日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    private void validatePaymentResultStatus(String status) {
        PaymentResultStatusEnum[] statusEnums = PaymentResultStatusEnum.values();
        for (PaymentResultStatusEnum statusEnum : statusEnums) {
            if(statusEnum.toString().equalsIgnoreCase(status)) {
                return;
            }
        }
        throw new BizException(BizError.parameterError(String.format("支付结果状态不正确！预期：SUCCESS、FAIL，实际：%s", status)));
    }
    
    /**
     * 
     * 功能描述：转换对象
     *
     * @param orderNo 订单号
     * @param paymentResult 支付结果
     * @return 
     * 
     * @author 刘曙
     *
     * @since 2023年9月20日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    private OrderPaymentResultDTO convertOrderPaymentResult(String orderNo, PaymentResultNotifyVO paymentResult) {
        List<OrderPaymentFlowDTO> flows = paymentResult.getPaymentLines().stream().filter(line -> {
            validatePaymentResultStatus(line.getStatus());
            if (PaymentResultStatusEnum.FAIL.toString().equalsIgnoreCase(line.getStatus())) {
                log.warn("收到订单流水支付失败通知！订单号：{}，业务订单号：{}，单据类型：{}，单号：{}，说明：{}", orderNo, paymentResult.getBizOrderNo(), line.getJournalType(), line.getJournalNo(), line.getRemark());
                return false;
            }
            return true;
        }).map(line -> {
            OrderPaymentFlowDTO flow = new OrderPaymentFlowDTO();
            BeanUtils.copyProperties(line, flow);
            flow.setBizDate(line.getPayTime());
            flow.setPaymentAccountCode(line.getPayMethodAccountCode());
            flow.setPaymentAccountName(line.getPayMethodAccountName());
            flow.setPaymentMethodCode(line.getPayMethodCode());
            flow.setPaymentMethodName(line.getPayMethodName());
            return flow;
        }).collect(Collectors.toList());
        
        return new OrderPaymentResultDTO(orderNo, paymentResult.getBizOrderNo(), flows);
    }
    
    /**
     * 
     * 功能描述：转化对象
     *
     * @param flowNos 流水号数组
     * @return 流水号响应对象
     * 
     * @author 刘曙
     *
     * @since 2023年9月20日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    private List<PaymentResultNotifyResultVO> convertPaymentResultNotifyResult(List<String> flowNos) {
        return flowNos.stream().map(flowNo -> new PaymentResultNotifyResultVO(flowNo)).collect(Collectors.toList());
    }
    /**
     *  
     * 功能描述：修改订单在线支付流水手续费和费率
     *
     * @param paymentChargeResult 手续费明细
     * @return 无
     * 
     * @author 刘曙
     *
     * @since 2023年9月17日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    @PutMapping("/payment/flow/charge")
    public ResponseEntity<?> paymentChargeResultNotifyByBizNo(@RequestBody @Validated PaymentChargeResultNotifyVO paymentChargeResult) {
        Order order = orderService.getByOrderBizNo(paymentChargeResult.getBizOrderNo());
        cn.hutool.core.lang.Assert.notNull(order, () -> new BizException(new BizError(BizHttpStatus.SC_NOT_FOUND, "ORDER_NOT_FOUND", String.format("无效的业务订单号！业务订单号：%s", paymentChargeResult.getBizOrderNo()))));
        
        List<PaymentChargeResultLineNotifyVO> lines = paymentChargeResult.getPaymentLines();
        cn.hutool.core.lang.Assert.notNull(order);
        
        orderPaymentFlowService.changeCharge(order.getId(), lines.stream().map(line -> {
                                                                            OrderPaymentFlowChargeDTO r = new OrderPaymentFlowChargeDTO();
                                                                            BeanUtils.copyProperties(line, r);
                                                                            r.setRate(line.getChargeRate());
                                                                            return r;
                                                                        }).collect(Collectors.toList()));
        return ResponseEntity.ok().body(null);
    }    
    
    /**
     *  
     * 功能描述：创建订单
     *
     * @param order 需要创建的订单数据
     * @return 订单号
     * 
     * @author 刘曙
     *
     * @since 2023年9月18日
     *
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     */
    @PostMapping
    public ResponseEntity<CreateOrderResultVO> create(@RequestBody @Validated NewOrderVO order) {
        // 将VO转化为 DTO实体
        NewOrderDTO orderDTO = OrderUtil.transferOrderDTO(order ) ;
        // 维护主数据 , 如: 支付方式、业务线和订单来源
        orderService.findAndInvokeBaseData(orderDTO ,order.getPaymentType() ,order.getBusinessLine(), order.getOriginChannel());
        // 创建订单
        CreateOrderResultDTO result = orderApi.create(orderDTO);
        return ResponseEntity.created(null).body(new CreateOrderResultVO(result.getOrderId(), result.getOrderNo()));
    }
}
